class BlackDeathHeroPawn extends BlackDeathPawn
	placeable;


var() float	UseableCheckRadius;

var name lastStateBeforeStagger; //where were we when I was staggered again?

//Weapon Animation
var AnimNodeBlendList HAttackType;
var AnimNodeBlendList VAttackType;
var AnimNodeBlend SwingVar;
var AnimNodeBlendByProperty ShoveNode;

var AnimNodeBlendList WeaponStateNode; //Node that blends equips

var int ShoveRange; //Maximum range of a shove
var int ShoveDamage; //how much damage shove does
var int ShoveMomentum; //mesure of how velocity to add upon shoveing a target

var float BurnLength;//How long Vincient will burn before automatically extinguishing

/** var to record the last weapon held so we can switch back when going back to attack */
var BlackDeathWeapon LastHeldWeapon;

var bool bEndAttackingState; //flag that is set if the pawn is leaving the attack state that notifies the pawn to transition

/** Running Varibles */
var() float DefaultRunSpeed; //How fast the players default speed is. Multipliers are used to alter speed based on this base.
var float CurrentBaseSpeed; //How fast the current base speed is, used to reset speed after apllying multipliers
var name stateBeforeRun; //The state the player was in before running

//Determines the maximum Stamina that player can have
var() int StaminaMax;

var int Stamina;//current stamina
var bool bForceFullCooldown;//Do we have to wiat for full colldown to run?

//Hold enumeration for what health state we're in
enum EHealthState
{
	EHS_Excellent,
	EHS_Fair,
	EHS_Bad,
	EHS_Dead
};

var int ExcellentMinHealth;//Minimum Health for the excellent Health state
var int FairMinHealth;//Minimum Health for the Good health state
//The current health level of the player
var EHealthState CurrentHealthState;

var AnimNodeBlendList HealthNode;

var int LocalHealthMax;//Max health for current health level
//Scalar for how much the camera should tilt with damage.
var float TiltDamageScale;


//END VARIBLES


simulated function PostBeginPlay()
{
	super.PostBeginPlay();
	Stamina = StaminaMax;
	CheckHealthState();
	//gotostate('default');
}


/*This Function is called after the AnimTre is initialized.
*Any nodes that we want to control code, we should look up here.
*/
	simulated event PostInitAnimTree(SkeletalMeshComponent SkelComp)
	{
		super.PostInitAnimTree(SkelComp);
		if (SkelComp == Mesh)
		{
			ShoveNode = AnimNodeBlendByProperty(Mesh.FindAnimNode('ShoveNode'));
			HealthNode = AnimNodeBlendList(Mesh.FindAnimNode('HeathState'));
			HAttackType = AnimNodeBlendList(Mesh.FindAnimNode('Horizontal'));
			VAttackType = AnimNodeBlendList(Mesh.FindAnimNode('Vertical'));
			SwingVar = AnimNodeBlend(Mesh.FindAnimNode('SwingVar'));
            AimNode = AnimNodeAimOffset( mesh.FindAnimNode('AimNode') );
			WeaponStateNode = AnimNodeBlendList( mesh.FindAnimNode('Weap_State'));
		}
}

/** Change the type of weapon animation we are playing. */
/*simulated function SetWeapAnimType(EWeapAnimType AnimType)
{
	if (AimNode != None)
	{
		switch(AnimType)
		{
			case EWAT_Default:
				AimNode.SetActiveProfileByName('Default');
				break;
			case EWAT_Pistol:
				AimNode.SetActiveProfileByName('SinglePistol');
				break;
			case EWAT_DualPistols:
				AimNode.SetActiveProfileByName('DualPistols');
				break;
			case EWAT_ShoulderRocket:
				AimNode.SetActiveProfileByName('ShoulderRocket');
				break;
			case EWAT_Stinger:
				AimNode.SetActiveProfileByName('Stinger');
				break;
		}
	}
}*/

function AddDefaultInventory()
{
	local int i;
	for (i=0; i < InitialInventory.Length; i++)
	{
		CreateInventory(InitialInventory[i]);
	}
}

simulated function SetHealthAnimType(EHealthState AnimType)
{
	if (HealthNode != None)
	{
		switch(AnimType)
		{
			case EHS_Excellent:
				HealthNode.SetActiveChild(0, 0.0);
				break;
			case EHS_Fair:
				HealthNode.SetActiveChild(1, 0.0);
				break;
			case EHS_Bad:
				HealthNode.SetActiveChild(2, 0.0);
				break;
			case EHS_Dead:
				break;
		}
	}
}

event TakeDamage(int Damage, Controller InstigatedBy, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser)
{
	Super.TakeDamage(Damage, InstigatedBy, HitLocation, Momentum, DamageType, HitInfo, DamageCauser);
	CheckHealthState();
	ClearTimer('StartRegenHealth');//Turn off any current regen so we can restart
	ClearTimer('IncrimentHealth');
	if(health > 0)
	{
		SetTimer(2.0, false, 'StartRegenHealth');
	}
}

simulated function StartRegenHealth()//Sets health to recover itself over time
{
	if(Health < LocalHealthMax)
	{
		Health += 1;
		SetTimer(0.5, true, 'IncrimentHealth');
	}
}

simulated function IncrimentHealth()
{
	if(Health < LocalHealthMax)
	{
		Health += 1;
		WorldInfo.Game.Broadcast(None, "health regened to "@Health);
	}
	else
	{
		ClearTimer('IncrimentHealth');
		WorldInfo.Game.Broadcast(None, 'Health is full at '@Health);
	}
}

function CheckHealthState()
{
	switch(CurrentHealthState)
	{
		//find the current health state based on the enums and check to see if we dropped below min health
		case EHS_Excellent:
			if(Health < ExcellentMinHealth)
			{
				setHealthState(EHS_Fair);
			}
			else
			{
				SetBaseSpeed(DefaultRunSpeed);
				break;
			}
		case EHS_Fair:
			if(health < FairMinHealth)
			{
				setHealthState(EHS_Bad);
			}
			else
			{
				SetBaseSpeed(DefaultRunSpeed*0.8);
				break;
			}
		case EHS_Bad:
			if(health <= 0)
			{
				setHealthState(EHS_dead);
			}
			else
			{
				SetBaseSpeed(DefaultRunSpeed*0.6);
				break;
			}
		case EHS_Dead:
			break;
	}
}

simulated function setHealthState(EHealthState newState)
{
	if(CurrentHealthState != newState)
	{
		switch(newState)
		{
			case EHS_Excellent: LocalHealthMax = HealthMax; break;
			case EHS_Fair: LocalHealthMax = ExcellentMinHealth -1; break;
			case EHS_Bad: LocalHealthMax = FairMinHealth-1; break;
			case EHS_Dead: LocalHealthMax = 0; break;
		}
		CurrentHealthState = newState;
		SetHealthAnimType(newState);
	}
}

simulated function ResetHealth()
{
	setHealthState(EHS_Excellent);
	Health = HealthMax;
	CheckHealthState();
}

simulated function Ignite()
{
	if(!bOnFire)
	{
		super.Ignite();
		SetTimer(BurnLength, false, 'Extinguish');
	}
}
simulated function Extinguish()
{
	if(bOnFire)
	{
		Super.Extinguish();
		ClearTimer('Extinguish');
	}
}

function SetBaseSpeed(float BaseSpeed)
{
	CurrentBaseSpeed = BaseSpeed;
	AirSpeed=BaseSpeed;
	GroundSpeed=BaseSpeed;
}

function ApplySpeedMultiplier(float Amount)
{
	AirSpeed = CurrentBaseSpeed*Amount;
	GroundSpeed = CurrentBaseSpeed*Amount;
}

function ResetSpeed()
{
	AirSpeed=CurrentBaseSpeed;
	GroundSpeed=CurrentBaseSpeed;
}

simulated function float CalcDamageTilt()//Sets how much the camera should tilt based on the player's health.
{
	if(LocalHealthMax <= 0)
	{
		return 0.f;
	}
	return Abs(Health-LocalHealthMax)/LocalHealthMax*10430.37826809827*TiltDamageScale;
}

state Default
{
	event BeginState(Name PreviousStateName)
	{
		`log("Entering normal state");
		if(BlackDeathCamera(PlayerController(Controller).PlayerCamera) != none)
		{
			PlayerController(Controller).SetCameraMode('FollowCam');
		}
		changeState(0, 0.2);
	}
}

/** running functions and controls */
State Running
{
	
	event BeginState(Name PreviousStateName)
	{
		stateBeforeRun = PreviousStateName;
		if(Stamina <= 0)//If we ran out of stamina before the run started.
		{
			goToState(stateBeforeRun);
		}
		else
		{
			ApplySpeedMultiplier(3.0);
			if(BlackDeathCamera(PlayerController(Controller).PlayerCamera) != none)
			{
				PlayerController(Controller).SetCameraMode('FollowCam');
				BlackDeathCamera(PlayerController(Controller).PlayerCamera).ToggleRunning();
			}
			SetTimer(0.1, true, 'DecrementStamina');
		}
	}
	
	
	function EndRun()
	{
		goToState(stateBeforeRun);
	}
	
	/* why is this still here?  -Allen
	function bool CanRun()
	{
		//return false;//No dog, you can't put a run in your run.
	}
	*/
	
	event EndState(Name NextStateName)
	{
		//consider adding a doRun() function to impliment the graphic effects of running aside from this low level stuff
		ResetSpeed();
		if(BlackDeathCamera(PlayerController(Controller).PlayerCamera) != none)
		{
			BlackDeathCamera(PlayerController(Controller).PlayerCamera).ToggleRunning();
		}
		ClearTimer('DecrementStamina');
		EndRun();
	}
}

simulated function StartRun()
{
	if(CanRun())//If we can run
	{
		goToState('Running');
	}
}
simulated function EndRun()
{
}

Simulated function Walk()
{
	ApplySpeedMultiplier(1.5);
}

function bool CanRun()
{
	return (Stamina > 0 && !bForceFullCooldown);
}


/** Stamina Functions and controls, go here for all stamina stuff, set Stamina manually and I will kill you! */
function DecreaseStamina(int Amount)
{
	if(Stamina > 0 /*&& !bForceFullCooldown*/)
	{
		Stamina -= Amount;
		Stamina = Max(Stamina, 0);
	}
	else
	{
		Stamina = 0;
	}
	if(Stamina <= 0)
	{
		ForceStaminaCoolDown();
	}
	StartRegenStamina();
}

function DecrementStamina()
{
	DecreaseStamina(1);
}

function StartRegenStamina()//Called to start regerating stamina
{
	EndReginStamina();
	SetTimer(3.0, false, 'BeginRecoverStamina');
}

function BeginRecoverStamina()
{
	RecoverStamina();
	if(Stamina < StaminaMax)
	{
		SetTimer(0.2, true, 'RecoverStamina');
	}
}

function EndReginStamina()
{
	clearTimer('RecoverStamina');
	clearTimer('BeginRecoverStamina');
}

function RecoverStamina()//Called to incriment stamina while running
{
	if(Stamina < StaminaMax)
	{
		Stamina +=1;
	}
	else
	{
		EndReginStamina();
	}
	if(Stamina >= 50)
	{
		if(bForceFullCooldown)
		{
			bForceFullCooldown = false;//Release the run lock
		}
	}
}

function ForceStaminaCoolDown()//function to handle when we run out of stamina
{
	ClearTimer('DecrementStamina');//dont decrease stamina anymore
	bForceFullCooldown = true;//Lock running
	EndRun();//full stop to cancel running
	StartRegenStamina();
}

function goToFirstPersonMode()
{
	if(canAim())
	{
		goToState('Aiming');
	}
}

simulated function bool canAim()
{
	return true;
}

State Aiming
{
	event BeginState(Name PreviousStateName)
	{
		//ApplySpeedMultiplier(0);
		bJumpCapable = false;
		PlayerController(Controller).SetCameraMode('FirstPerson');
		PlayerController(Controller).IgnoreMoveInput(true);
		ChangeVisibility(false);
	}
	
	simulated function bool canAim()
	{
		return False;
	}
	
	function goToFirstPersonMode()
	{
		goToState('Default');
	}
	
	simulated function name GetDefaultCameraMode(PlayerController RequestedBy)
	{
		return 'FirstPerson';
	}
	
	event EndState(Name NextStateName)
	{
		//ResetSpeed();
		bJumpCapable = true;
		PlayerController(Controller).IgnoreMoveInput(false);
		ChangeVisibility(true);
	}
}

simulated function StartFire(byte FireModeNum)
{
	if(canShove())
	{
		Shove();
	}
}

function bool canShove()
{
	return true;
}

simulated function doShove()
{
}

function FinishShove()
{
}

function Shove()
{
	goToState('Shoveing');
}

state Shoveing
{
	event BeginState(Name PreviousStateName)
	{
		changestate(2, 0.2);
		ShoveNode.PlayAnim(false,1.0,0.0);
		bJumpCapable = false;
		PlayerController(Controller).IgnoreMoveInput(true);
		doShove();
	}
	
	simulated function doShove()
	{
		local vector OtherLoc;
		local vector loc;
		local Pawn P;
		ForEach OverlappingActors(class'Pawn', P, ShoveRange, location)
		{
			if(P != self)//IGNORE YOURSELF!!!
			{
				Otherloc = P.Location;
				OtherLoc.z = 0;
				loc = location;
				loc.z = 0;
				if((OtherLoc dot Loc) > 0.75)
				{
					P.TakeDamage(ShoveDamage, Controller, Location, Vector(Rotation)*ShoveMomentum, class'DmgType_Crushed');
					BlackDeathPawn(P).Stagger();
				}
			}
		}
	}
	
	function FinishShove()
	{
		goToState('Default');
	}
	
	event EndState(Name NextStateName)
	{
		ResetSpeed();
		PlayerController(Controller).IgnoreMoveInput(false);
		bJumpCapable = true;
		changestate(0, 0.2);
	}
}

simulated function bool Finisher()
{
	return false;
}

simulated function ToggleWalk()
{
	ApplySpeedMultiplier(0.5);
}
simulated function ToggleRun()
{
	ResetSpeed();
}


function ToggleAttacking()
{
	if(CanBeginAttackState())
	{
		goToState('Attacking');
	}
}

//If we can switch to attacking right now
function bool CanBeginAttackState()
{
	return true;
}

state Attacking
{
	event BeginState(Name PreviousStateName)
	{
		`log("entering attack ");
		PrepareWeapon(PreviousStateName);
		changeState(1, 0.2);
	}
	
	simulated function bool Finisher()
	{
		if( bNoWeaponFiring )
		{
			return false;
		}
		gotostate('Finishing');
		return true;
	}
	
	simulated function StartFire(byte FireModeNum)
	{
		if( bNoWeaponFIring )
		{
			return;
		}

		if( Weapon != None )
		{
			Weapon.StartFire(FireModeNum);
		}
	}
	
	function AnimAttachWeaponToHand()
	{
		Super.AnimAttachWeaponToHand();
		if(PlayerController(Controller).PlayerCamera.CameraStyle != 'ThirdPerson')
		{
			PlayerController(Controller).SetCameraMode('ThirdPerson');
		}
	}
	
	function ToggleAttacking()
	{
		bEndAttackingState = true;
		RemoveWeapon();
	}
	
	simulated function bool canAim()
	{
		return False;
	}
	
	function bool canBeStaggered()
	{
		return false;
	}
	
	function bool canShove()
	{
		return false;
	}
	
	function FinishUnequip()
	{
		Super.FinishUnequip();
		if(bEndAttackingState)
		{
			goToState('Default');
		}
	}
	
	function bool CanBeginAttackState()
	{
		return false;
	}
	
	function PrepareWeapon(Name previousState)
	{
		if(!isAttackState(previousState))
		{
			if(LastHeldWeapon == None)
			{
				InvManager.SwitchToBestWeapon();
			}
			else
			{
				InvManager.SetCurrentWeapon(LastHeldWeapon);
			}
		}
	}
	
	function RemoveWeapon()
	{
		Weapon.ForceEndFire();
		LastHeldWeapon = BlackDeathWeapon(Weapon);
		InvManager.SetCurrentWeapon(None);
		
	}
	
	event EndState(Name NextStateName)
	{
		bEndAttackingState = false;
		if ( NextStateName == 'running' ){
			LastHeldWeapon = BlackDeathWeapon(Weapon);
		}
	}
}

simulated function NotifyAttacking()
{
	ApplySpeedMultiplier(0.1);
}

simulated function NotifyEndAttaking()
{
	ResetSpeed();
}

simulated function NotifyPawnWeaponActive()
{
	WeaponStateNode.SetActiveChild(2, 0.2);
}

state Finishing extends Attacking
{
	event BeginState(Name PreviousStateName)
	{
		`log("Moveing to finsher state");
		changestate(4, 0.2);
		//StateNode.PlayAnim(false,1.0,0.0);
		bJumpCapable = false;
		PlayerController(Controller).IgnoreMoveInput(true);
		//doFinisher();
	}
	
	simulated function doFinisher()
	{
		local BlackDeathPawn BDP;
		ForEach OverlappingActors(class'BlackDeathPawn', BDP, 100)
		{
			if(BlackDeathZombiePawn(BDP) != none)
			{
				if(BlackDeathZombiePawn(BDP).isinState('incapped'))
				{
					BDP.TakeDamage(1, controller, location, vect(0,0,0), class'DmgType_Finish');
				}
			}
		}
	}
	
	function FinshFinsher()
	{
		goToState('Attacking');
	}
	
	event EndState(Name NextStateName)
	{
		`log("Leaving fisher state");
		PlayerController(Controller).IgnoreMoveInput(false);
		bJumpCapable = true;
		//changestate(0, 0.2);
	}
	
	function ToggleAttacking()
	{
	}
	
	simulated function StartFire(byte FireModeNum)
	{

	}
	
	simulated function StopFire(byte FireModeNum)
	{

	}
	
	function bool canShove()
	{
		return false;
	}
}

function bool isAttackState(Name Statename)
{
	return Statename == 'Finishing';
}

function WeaponAnim()
{
	local BDMelee_GreatSword Weap;
	Weap = BDMelee_GreatSword(Weapon);
	if(Weap != none)
	{
		AnimNodeSequence(SkeletalMeshComponent(Weap.Mesh).FindAnimNode('Weapon_Finisher')).playAnim(false, 1.0, 0.0);
		//SkeletalMeshComponent(Weap.Mesh).playAnim('sword');
	}
}

simulated function PlayWeaponEquip()
{
	`log(Self@": Playing Equip");
	WeaponStateNode.SetActiveChild(0, 0.2);
	WeaponStateNode.PlayAnim(false,1.0,0.0);
}

simulated function PlayWeaponPutDown()
{
	`log(Self@": Playing Unequip");
	WeaponStateNode.SetActiveChild(3, 0.0);
	WeaponStateNode.PlayAnim(false,1.0,0.0);
}

simulated function PlayWeaponSwing()
{
	`log(Self@": Playing Swing");
	WeaponStateNode.SetActiveChild(1, 0.2);
	WeaponStateNode.PlayAnim(false,1.0,0.0);
}

simulated function EndSwing()
{
	local BlackDeathWeapon BDW;
	`log(Self@": Playing end swing");
	WeaponStateNode.SetActiveChild(2, 0.2);
	BDW = BlackDeathWeapon(weapon);
	if(BDW != none)
	{
		BDW.EndSwing();
	}
	
}


State Staggered
{
	event BeginState(Name PreviousStateName)
	{
		lastStateBeforeStagger = PreviousStateName;
		ApplySpeedMultiplier(0.5);
		changeState(3, 0.2);
		setTimer(1.0, false, 'StaggerRecover');
	}
	
	simulated function StaggerRecover()
	{
		goToState(lastStateBeforeStagger);
	}
	
	function bool CanBeginAttackState()
	{
		return false;
	}
	
	function bool canShove()
	{
		return false;
	}
	
	simulated function bool canAim()
	{
		return false;
	}
	
	function bool canRun()
	{
		return false;
	}
	
	event EndState(Name NextStateName)
	{
		ResetSpeed();
		changeState(0, 0.2);
		clearTimer('StaggerRecover');
	}
}

simulated function PlayDying(class<DamageType> DamageType, vector HitLoc)
{
  Super.PlayDying(DamageType, HitLoc);
  Health = 0;
  CheckHealthState();
  clearTimer('RecoverStamina');
  SetTimer(0.5, false, 'Respawn');
}

function Respawn()
{
}

DefaultProperties
{
	InventoryManagerClass=class'BlackDeathHeroInventoryManager'
//Setting up the light environment
//Setting up the mesh and animset components
    Begin Object Name=InitialSkeletalMesh
        CastShadow=true
        bCastDynamicShadow=true
        bOwnerNoSee=false
        LightEnvironment=MyLightEnvironment;
		BlockRigidBody=true;
		CollideActors=true;
		BlockZeroExtent=true;
//What to change if you'd like to use your own meshes and animations
        PhysicsAsset=PhysicsAsset'BD_CHARACTERS.Mesh.Vincent_Physics'
        AnimSets(0)=AnimSet'BD_CHARACTERS.Animation.VincentMoveSet'
        AnimTreeTemplate=AnimTree'BD_Characters.Animation.Human_AnimTree'
        SkeletalMesh=SkeletalMesh'BD_CHARACTERS.Mesh.Vincent_McGawain'
    End Object
//Setting up a proper collision cylinder
    Mesh=InitialSkeletalMesh;
    Components.Add(InitialSkeletalMesh); 
	CollisionType=COLLIDE_BlockAll
	Begin Object Name=CollisionCylinder
		CollisionRadius=+0024.000000
		CollisionHeight=+0044.000000
	End Object
	CylinderComponent=CollisionCylinder
	
	BurnLength = 5.0
	
	TiltDamageScale = 1.5
	HealthMax = 100
	CurrentHealthState = EHS_Excellent
	LocalHealthMax = 100
	ExcellentMinHealth = 67
	FairMinHealth = 34
	StaminaMax = 1000
	bForceFullCooldown = false
	
	UseableCheckRadius = 75
	BaseEyeHeight = 36
	
	DefaultRunSpeed = 75.000000
	
	bEndAttackingState=false
	
	ShoveRange = 100
	ShoveDamage = 25
	ShoveMomentum = 50
	
	AirSpeed=150.000000
	GroundSpeed=80.000000
	bCanCrouch=true
	bCanClimbLadders=True
	bCanPickupInventory=True
	bCanBeDamaged=true
	bCanSwim=true
	
	InitialInventory(0)=class'BDMelee_Torch'
	InitialInventory(1)=class'BDMelee_GreatSword'
}
